/**
 * 
 */
package denaris.core.entity;

import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;

import denaris.core.AbstractDenarisMap;
import denaris.core.ExhaustSystem;
import denaris.core.PlayerBulletSystem;
import denaris.core.SatelliteTypes;
import denaris.core.Scorebar;
import denaris.core.Statusbar;
import denaris.core.controller.AbstractController;
import denaris.core.controller.PlayerController;
import denaris.factory.FrameFactory;
import denaris.factory.ImageFactory;
import denaris.midlet.Denaris;
import denaris.midlet.DenarisGameCanvas;
import denaris.midlet.GameScreen;

/**
 * Represents the player ship along with all possible features like sattelites
 * and stuff.
 * 
 * @author stkl23
 * 
 */
public class Player extends AbstractEntity {
	private ExhaustSystem fume;

	private Sprite shield = new Sprite(ImageFactory
			.getImage("/denaris/resource/sprite/shield.png"), 50, 36);

	/** indicates the number of miliseconds that the shield stays active */
	private long shieldDuration = 7500;

	/**
	 * is set when the player collects a shield item and is checked against
	 * shieldDuration every frame
	 */
	private long shieldTime = 0;

	/**
	 * indicates that the field should flicker - this happens when it is about
	 * to be turned off
	 */
	private boolean shieldFlicker = false;

	private Sprite satellite = null;

	/** the evolution of the satellite - there are three different levels */
	private int satelliteLevel = 0;
	
	/** the number of missile collectibles (green) that the player has collected */
	private int missileCount = 0;

	/** the number of shield items collected */
	private int shieldCount = 0;
	
	/** the number of red items collected */
	private int shotCount = 0;
	
	private int lifeCount = 3;
	
	public Player(AbstractDenarisMap parentMap) {
		super(parentMap, 0);
		// set the sprite
		Image img = ImageFactory
				.getImage("/denaris/resource/sprite/player_sprite_scaled.png");
		Sprite s = new Sprite(img, 30, 12);
		controller.setSprite(s);
		// create the primary Bullet System
		setPrimaryBulletSystem(new PlayerBulletSystem(parentMap));
		// create the exhaust system
		fume = new ExhaustSystem();
		// setup the shield
		shield.setFrameSequence(FrameFactory.createLoopbackSequence(0, 3, 4));
		shield.defineReferencePixel(8, 12);
		shield.setVisible(false);
	}

	public void checkCollision() {
		Sprite s = controller.getSprite();
		// check collision with enemies
		Vector enemies = parentMap.getEnemies();
		Enumeration e = enemies.elements();
		while (e.hasMoreElements()) {
			AbstractEntity enemy = (AbstractEntity) e.nextElement();
			// check if the enemy collides with the shield
			if (shield.isVisible() && enemy.collidesWith(shield, false)) {
				// the shield destroys every enemy
				enemy.explode(0, 0);
				updateScore(enemy.getScore());
			} else {
				if (satellite != null && enemy.collidesWith(satellite, false)) {
					// satellite collision also destroys the enemy
					enemy.explode(0, 0);
					updateScore(enemy.getScore());
				} else if (enemy.collidesWith(s, true)) {
					notifyCollision(enemy);
				}
			}
		}
		// check collision with friends
		Vector friends = parentMap.getFriends();
		e = friends.elements();
		while (e.hasMoreElements()) {
			AbstractEntity g = (AbstractEntity) e.nextElement();
			if (g instanceof Collectible && g.collidesWith(s, false)) {
				// handle the collectible right here in the player class
				handleCollectible((Collectible) g);
			}
		}
		
		// check collision with map
		if (parentMap.collidesWith(s)) {
			notifyCollision(parentMap);
		}
		
		// check bullet collision
		getPrimaryBulletSystem().checkCollision(enemies);
	}

	private void handleCollectible(Collectible coll) {
		// remove the collectible from the list
		parentMap.removeFriend(coll);
		// update score
		updateScore(coll.getScore());
		// is it a satellite ?
		if (coll instanceof Satellite) {
			handleSatellite((Satellite) coll);
		} else {
			PlayerBulletSystem playerBulletSystem = (PlayerBulletSystem) getPrimaryBulletSystem();
			Graphics buffer = DenarisGameCanvas.getInstance().getBuffer();
			Statusbar statusbar = Statusbar.getInstance();
			// check the type
			switch (coll.getType()) {
			case Collectible.COLLECTIBLE_SHOT: {
				if (shotCount < 18) {
					shotCount++;
					playerBulletSystem.getPrimaryEmitter().nextBulletFrame();
					statusbar.redrawCollectibles(buffer, Collectible.COLLECTIBLE_SHOT, shotCount);
				}
				break;
			}
			case Collectible.COLLECTIBLE_NUKE: {
				// nuke all friends and enemies
				nuke(parentMap.getFriends());
				nuke(parentMap.getEnemies());
				break;
			}
			case Collectible.COLLECTIBLE_MISSILES: {
				if (missileCount < 12) {
					missileCount++;
				}
				if (missileCount == 1) {
					// we must activate the first missile emitter
					playerBulletSystem.getMissileSouthEast().setActive(true);
				}else if(missileCount == 7) {
					playerBulletSystem.getMissileNorthEast().setActive(true);
				}
				statusbar.redrawCollectibles(buffer, Collectible.COLLECTIBLE_MISSILES, missileCount);
				break;
			}
			case Collectible.COLLECTIBLE_SCORE: {
				break;
			}
			case Collectible.COLLECTIBLE_SHIELD: {
				// activate the shield
				Sprite s = controller.getSprite();
				shield.setRefPixelPosition(s.getX(), s.getY());
				shield.setVisible(true);
				shieldTime = System.currentTimeMillis();
				// increase the time that the shield stays active
				shieldDuration += 500;
				shieldFlicker = false;
				if (shieldCount < 18) {
					shieldCount++;
					statusbar.redrawCollectibles(buffer, Collectible.COLLECTIBLE_SHIELD, shieldCount);
				}
				break;
			}
			}
		}
	}

	private void activateSecondaryWeaponBySatelliteType(Satellite sat) {
		switch(sat.getType()) {
		case SatelliteTypes.REFLECTOR:{
			getPlayerBulletSystem().activateReflector();
			break;
		}
		case SatelliteTypes.NINJA:{
			getPlayerBulletSystem().activateNinja();
			break;
		}
		case SatelliteTypes.LASER:{
			getPlayerBulletSystem().activateLaser();
			break;
		}
		}
	}
	
	private void handleSatellite(Satellite sat) {
		if (sat.getType() == SatelliteTypes.SLOWER
				&& PlayerController.PLAYER_SPEED > 1) {
			// slow down
			PlayerController.PLAYER_SPEED--;

		} else if (sat.getType() == SatelliteTypes.TURBO
				&& PlayerController.PLAYER_SPEED < 6) {
			// speed up
			PlayerController.PLAYER_SPEED++;
		} else {
			Sprite s = controller.getSprite();
			// create or extend the satellite
			if (satelliteLevel == 0) {
				satellite = new Sprite(ImageFactory
						.getImage("/denaris/resource/sprite/satellite1.png"),
						14, 10);
				satellite
						.setFrameSequence(FrameFactory.createSequence(0, 2, 4));
				satellite.defineReferencePixel(-30, -1);
				satellite.setRefPixelPosition(s.getX(), s.getY());
				satelliteLevel++;
			} else if (satelliteLevel == 1) {
				satellite = new Sprite(ImageFactory
						.getImage("/denaris/resource/sprite/satellite2.png"),
						17, 11);
				satellite
						.setFrameSequence(FrameFactory.createSequence(0, 3, 4));
				satellite.defineReferencePixel(-30, 0);
				satellite.setRefPixelPosition(s.getX(), s.getY());
				satelliteLevel++;
				
			} else if (satelliteLevel == 2) {
				satellite = new Sprite(ImageFactory
						.getImage("/denaris/resource/sprite/satellite3.png"),
						18, 15);
				satellite
						.setFrameSequence(FrameFactory.createSequence(0, 6, 4));
				satellite.defineReferencePixel(-30, 1);
				satellite.setRefPixelPosition(s.getX(), s.getY());
				satelliteLevel++;
			}
			
			if (satelliteLevel >= 2) {
				// change the secondary weapon
				activateSecondaryWeaponBySatelliteType(sat);
			}
		}

	}

	private void nuke(Vector v) {
		for (int i = v.size() - 1; i >= 0; i--) {
			AbstractEntity group = (AbstractEntity) v.elementAt(i);
			if (!(group instanceof Explosion)) {
				group.explode(0, 0);
			}
		}
	}

	public AbstractController createController() {
		return new PlayerController(getParentMap());
	}

	public void update() {
		super.update();
		Sprite sprite = controller.getSprite();
		final int x = sprite.getX();
		final int y = sprite.getY();
		// check for fire button
		if (DenarisGameCanvas.keyStates[DenarisGameCanvas.KEY_FIRE]) {
			getPrimaryBulletSystem().emitt(x, y + 2);
		}
		// update the weapons
		primary.update();
		// update fume
		fume.update();
		// create fume particle
		fume.emitt(x, y + 6 + GameScreen.RANDOM.nextInt() % 4);

		if (shield.isVisible()) {
			// animate and update the shield
			shield.nextFrame();
			shield.setRefPixelPosition(x, y);
			long currentTimeMillis = System.currentTimeMillis();
			if (currentTimeMillis - shieldTime > shieldDuration) {
				// time to turn the shield off
				shield.setVisible(false);
			} else if (currentTimeMillis - shieldTime > shieldDuration - 2000) {
				// the shield will be turned off in 2 seconds - make it flicker
				// so the player knows
				shieldFlicker = true;
			}
		}

		// update the satellite
		if (satellite != null) {
			satellite.nextFrame();
			satellite.setRefPixelPosition(x, y);
		}
	}

	public void paint(Graphics g) {
		super.paint(g);
		// paint fume
		fume.paint(g);
		// paint weapons
		primary.paint(g);
		if (satellite != null) {
			// paint the satellite
			satellite.paint(g);
		}
		if ((shieldFlicker && DenarisGameCanvas.CURRENT_FRAME % 2 == 1)
				|| !shield.isVisible()) {
			// do nothing
		} else {
			// paint shield
			shield.paint(g);
		}
	}

	public Explosion explode(int childExplosions, int frameDelay) {
		Explosion explosionGroup = super.explode(childExplosions, frameDelay);
		AbstractDenarisMap map = getParentMap();
		map.addFriend(explosionGroup);
		// replace the player with a dummy that does nothing
		map.setPlayerGroup(new Dummy(map));
		// notify the game screen that we died so the fade out screen can be initiated
		Denaris.getInstance().notifyPlayerDied();
		return explosionGroup;
	}

	public void onScopeLeft() {
	}
	
	private PlayerBulletSystem getPlayerBulletSystem() {
		return (PlayerBulletSystem) getPrimaryBulletSystem();
	}

	public int getLifeCount() {
		return lifeCount;
	}

	public void decLifeCount() {
		this.lifeCount--;
	}
	
	public void updateScore(int delta) {
		score += delta;
		// refresh the score
		Scorebar.getInstance().drawScore(DenarisGameCanvas.getInstance().getBuffer(), score);
	}
	
	public int getMissileCount() {
		return missileCount;
	}

	public int getShieldCount() {
		return shieldCount;
	}

	public int getShotCount() {
		return shotCount;
	}
	
	public void reset() {
		shield.setVisible(false);
		satellite = null;
		satelliteLevel = 0;
		// reset the controller
		getController().reset();
		// reset the weapons
		getPrimaryBulletSystem().reset();
		// reset the fume particles
		fume.reset();
	}
}
